﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using info.lundin.Math;
using System.Threading;

namespace Urbini.Fabio._5BI.Integrali
{
    // Problema : I numeri non sono generati casualmente
    public class IntegraleDefinito
    {
        List<double> X = new List<double>();
        List<double> Y = new List<double>();
        string funcstr;
        double h, SX, DX;
        int Intervalli;
        Hashtable hash;
        ExpressionParser e;

        public IntegraleDefinito(string funzione, double Intervalli, double a, double b)
        {
            this.Intervalli = (int)Intervalli;
            h = (b - a) / (Intervalli);
            SX = a;
            DX = b;
            funcstr = funzione;
        }
        public IntegraleDefinito(Parametro parametro)
        {
            this.Intervalli = (int)parametro.intervalli;
            this.SX = parametro.a;
            this.DX = parametro.b;
            this.funcstr = parametro.funzione;
            h = (parametro.b - parametro.a) / (Intervalli);
        }
        double Funzione(double x)
        {
            ExpressionParser e = new ExpressionParser();
            hash = new Hashtable();

            // Vengono RIMOSSI TUTTI GLI SPAZI 
            funcstr = funcstr.Trim();
            // Aggiunto oggetto key,value
            hash["x"] = Convert.ToString(x);
            return e.Parse(funcstr, hash);
        }
        public double Rettangoli
        {
            get
            {
                double integrale = 0;
                double x1 = SX, x2 = SX;

                for (int i = 0; i < Intervalli; i++)
                {
                    x1 = x2;
                    x2 = x1 + h;

                    double Altezza = Funzione(x2);
                    integrale += Altezza;
                }
                return integrale * h;
            }
        }
        public double Trapezi
        {
            get
            {
                double integrale = (Funzione(SX) + Funzione(DX)) / 2;
                double x1 = SX, x2 = SX;

                x1 = x2;
                x2 = x1 + h;

                for (int i = 1; i < Intervalli - 1; i++)
                {
                    x1 = x2;
                    x2 = x1 + h;
                    double Altezza = Funzione(x2);
                    integrale += Altezza;
                }
                return integrale * h;
            }
        }
        public double Parabole
        {
            get
            {
                double coeff = 2;
                double SommatoriaY = Funzione(SX) + Funzione(DX);
                double x = SX + h;
                int idx = 1;

                while (Math.Round(x, 4) != DX)
                {
                    // Se è pari, il coefficente è 2
                    if (idx % 2 == 0) coeff = 2;
                    else coeff = 4;

                    SommatoriaY += coeff * Funzione(x);
                    x += h;
                    idx++;
                }
                return SommatoriaY * h / 3.000;
            }
        }
    }
    public class ErroreTrapezio
    {
        double errore = 0;
        public double Error { get { return errore; } }

        // Costruttori con overloading
        public ErroreTrapezio(string funzione, double intervalli, double a, double b)
        {
            double JN = new IntegraleDefinito(funzione, intervalli, a, b).Trapezi;
            double J2N = new IntegraleDefinito(funzione, intervalli * 2, a, b).Trapezi;
            errore = Math.Abs(J2N - JN) / 3;
        }
        public ErroreTrapezio(Parametro par)
        {
            double JN = new IntegraleDefinito(par).Trapezi;
            double J2N = new IntegraleDefinito(
                new Parametro(par.funzione,par.intervalli*2, par.a,par.b)).Trapezi;
            errore = Math.Abs(J2N - JN) / 3;
        }
        public ErroreTrapezio(Parametro par, IntegraleDefinito id)
        {
            double JN = id.Trapezi;
            double J2N = new IntegraleDefinito(
                new Parametro(par.funzione, par.intervalli * 2, par.a, par.b)).Trapezi;
            errore = Math.Abs(J2N - JN) / 3;
        }
    }
    public class ErroreParabola
    {
        double J2N = 0;
        double errore = 0;
        public double Error { get { return errore; } }
        public double IntegraleApprossimato { get { return J2N; } }

        public ErroreParabola(Parametro par, IntegraleDefinito id)
        {
            double JN = id.Parabole;
            J2N = new IntegraleDefinito(
                new Parametro(par.funzione, par.intervalli * 2, par.a, par.b)).Parabole;
            errore = Math.Abs(J2N - JN) / 15;
        }
    }
    public class Parametro
    {
        public double a, b, intervalli;
        public string funzione;

        public Parametro(string funzione, double intervalli, double a, double b)
        {
            this.funzione = funzione;
            this.a = a;
            this.b = b;
            this.intervalli = intervalli;
        }
    }
    public class Montecarlo
    {
        protected double a = 0, b = 0;
        protected int n = 0;

        public double Area
        {
            get
            {
                return M * (b - a) * c;
            }
        }
        public double c
        {
            get
            {
                int casiFavorevoli = 0;
                for (int i = 0; i < n; i++)
                {
                    double y = Y();
                    double x = X();
                    double fx = Fx(x);
                    if (y < fx) casiFavorevoli++;
                    Thread.Sleep(1);
                }
                return casiFavorevoli;
            }
        }
        public double M
        {
            get { return Fx(b); }
        }


        // Metodi
        protected double Fx(double x)
        {
            // usare il parser qui
            return 0;
        }
        protected double Y()
        {
            // Restituisce una Y casuale
            Random generator = new Random(DateTime.Now.Millisecond);
            return generator.NextDouble() * b;
        }
        protected double X()
        {
            Random generator = new Random(DateTime.Now.Millisecond);
            double num = generator.NextDouble();
            return -a + num * 2 * a;
        }
    }
    public class MontecarloEllisse : Montecarlo
    {
        public new double Area
        {
            get
            {
                // Area Ellisse
                return (2 * a * b) * (c / Convert.ToDouble(n)) * 2;
            }
        }
        public new double c
        {
            get
            {
                int casiFavorevoli = 0;
                for (int i = 0; i < n; i++)
                {
                    double y = Y();
                    double x = X();
                    double fx = Fx(x);
                    if (y < fx) casiFavorevoli++;
                    Thread.Sleep(2);
                }

                return casiFavorevoli;
            }
        }
        // Costruttori
        public MontecarloEllisse()
        {

        }
        public MontecarloEllisse(double a, double b, int n)
        {
            if (a < 0) throw new Exception("a non positivo");
            if (b < 0) throw new Exception("b non positivo");
            if (n < 0) throw new Exception("n non positivo");
            this.a = a;
            this.b = b;
            this.n = n;
        }
        // Metodi
        new double Fx(double x)
        {
            return (b / a) * Math.Sqrt(a * a - x * x);
        }
        new double Y()
        {
            Random generator = new Random();
            return generator.NextDouble() * b;
        }
        new double X()
        {
            Random generator = new Random();
            double num = generator.NextDouble();
            return -a + num * 2 * a;
        }
    }
}
